package top.yehot.kettle.boot.core.utils;

import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.Job;
import org.quartz.JobBuilder;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.springframework.stereotype.Component;

import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import top.yehot.cmm.util.core.base.BaseException;
import top.yehot.kettle.boot.core.task.KettleJobListener;
import top.yehot.kettle.boot.enums.KettleResEnum;
import top.yehot.kettle.boot.models.dto.TaskDto;

/**
 * quartz定时任务工具类，对任务进行管理（创建、修改、删除、暂停）
 * 
 * @author lquan
 * @date 2022年6月6日 上午12:18:34
 */
@Slf4j
@Component
@AllArgsConstructor
public class QuartzUtil {
	
	private final Scheduler scheduler;

	/**
	 * 获取触发器状态
	 *
	 * @param triggerName      触发器名
	 * @param triggerGroupName 触发器分组名
	 * @return 状态（NONE-不存在，NORMAL-正常，PAUSED-暂停，COMPLETE-完成，ERROR-错误，BLOCKED-阻塞）
	 */
	public String getTriggerState(String triggerName, String triggerGroupName) {
		TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName);
		try {
			Trigger.TriggerState triggerState = scheduler.getTriggerState(triggerKey);
			return triggerState.name();
		} catch (SchedulerException e) {
			log.error(KettleResEnum.QUARTZ_TRIGGER_STATE_ERR.getMsg(), e);
			throw new BaseException(KettleResEnum.QUARTZ_TRIGGER_STATE_ERR);
		}
	}
	
	/**
	 * 创建添加定时任务
	 *
	 * @param param 任务参数
	 */
	public void addCronJob(TaskDto param) {
		// 判断定时任务是否存在
		String triggerState = getTriggerState(param.getTriggerName(), param.getTriggerGroupName());
		try {
			// 触发器存在
			if (!Trigger.TriggerState.NONE.name().equals(triggerState)) {
				stopTriggerJob(param);
			}
			
			JobDetail jobDetail = createJobDetail(param.getJobName(), param.getJobGroupName(), param.getJobDataMap(), param.getJobClass());
			CronTrigger cronTrigger = createCronTrigger(param.getTriggerName(), param.getTriggerGroupName(), param.getCron());
				
			// 绑定触发器和调度任务
			scheduler.scheduleJob(jobDetail, cronTrigger);
			// 绑定监听
			scheduler.getListenerManager().addJobListener(new KettleJobListener());
			// 启动
			scheduler.start();
		} catch (Exception e) {
			log.error(KettleResEnum.QUARTZ_BIND_JOB_TRIGGER_ERR.getMsg(), e);
			throw new BaseException(KettleResEnum.QUARTZ_BIND_JOB_TRIGGER_ERR);
		}
	}
	
	/**
     * 移除定时任务
     *
     * @param taskName 任务名称
     */
    public void removeJob(String taskName) {
    	// 封装参数
    	TaskDto taskDto = TaskDto.packageDto(taskName, null, null);
        
    	// 定时任务不存在就不处理
        String triggerState = getTriggerState(taskDto.getTriggerName(), taskDto.getTriggerGroupName());
        if (Trigger.TriggerState.NONE.name().equals(triggerState)) {
            return;
        }
        
        // 定时任务存在，删除
        try {
        	stopTriggerJob(taskDto);
        } catch (Exception e) {
        	log.error(KettleResEnum.QUARTZ_DEL_TASK_ERR.getMsg(), e);
			throw new BaseException(KettleResEnum.QUARTZ_DEL_TASK_ERR);
        }
    }
	
	
	/**
	 * 任务执行实例
	 *
	 * @param jobName      任务名称
	 * @param jobGroupName 任务分组名
	 * @param jobDataMap   执行参数
	 * @param jobClass     执行类-实现了{@code org.quartz.Job}接口的类
	 * @return {@link JobDetail}
	 */
	private JobDetail createJobDetail(String jobName, String jobGroupName, JobDataMap jobDataMap, Class<? extends Job> jobClass) {
		// 获取任务执行类的实例
		JobBuilder jobBuilder = JobBuilder.newJob(jobClass);
		// 添加任务名，任务组
		jobBuilder.withIdentity(jobName, jobGroupName);
		// 添加任务执行的参数
		if (jobDataMap != null && jobDataMap.size() > 0) {
			jobBuilder.setJobData(jobDataMap);
		}
		// 获取job执行实例
		return jobBuilder.build();
	}
	
	/**
	 * cron触发器
	 *
	 * @param triggerName      触发器名
	 * @param triggerGroupName 触发器分组名
	 * @param cron             定时策略
	 * @return {@link CronTrigger}
	 */
	private CronTrigger createCronTrigger(String triggerName, String triggerGroupName, String cron) {
		// 触发器
		TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();
		// 触发器名,触发器组
		triggerBuilder.withIdentity(triggerName, triggerGroupName);
		// 触发器时间设定
		triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(cron).withMisfireHandlingInstructionDoNothing());
		// 从当前时间判断触发
		triggerBuilder.startNow();
		// 创建Trigger对象
		return (CronTrigger) triggerBuilder.build();
	}
	
	/**
	 * 停止定时任务
	 *
	 * @param param 任务参数
	 */
	private void stopTriggerJob(TaskDto param) throws Exception {
		TriggerKey triggerKey = TriggerKey.triggerKey(param.getTriggerName(), param.getTriggerGroupName());
        JobKey jobKey = JobKey.jobKey(param.getJobName(), param.getJobGroupName());
        try {
        	// 停止触发器
            scheduler.pauseTrigger(triggerKey);
            // 停止任务
            scheduler.interrupt(jobKey);
            
            // 移除触发器
            scheduler.unscheduleJob(triggerKey);
            // 移除任务
            scheduler.deleteJob(jobKey);
        } catch (SchedulerException e) {
        	throw e;
        }
	}
	
}
